package audit

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"time"
)

// Logger 审计日志记录器
type Logger struct {
	logDir    string
	backupDir string
	logLevel  string
}

// NewLogger 创建新的审计日志记录器
func NewLogger(logDir, backupDir, logLevel string) (*Logger, error) {
	// 确保目录存在
	if err := os.MkdirAll(logDir, 0755); err != nil {
		return nil, fmt.Errorf("创建日志目录失败: %w", err)
	}
	if err := os.MkdirAll(backupDir, 0755); err != nil {
		return nil, fmt.Errorf("创建备份目录失败: %w", err)
	}

	return &Logger{
		logDir:    logDir,
		backupDir: backupDir,
		logLevel:  logLevel,
	}, nil
}

// AuditEntry 审计记录条目
type AuditEntry struct {
	Timestamp     time.Time `json:"timestamp"`
	Operation     string    `json:"operation"`      // "add", "remove", "move"
	Thumbprint    string    `json:"thumbprint"`
	Subject       string    `json:"subject"`
	Issuer        string    `json:"issuer"`
	SerialNumber  string    `json:"serial_number"`
	SourceStore   string    `json:"source_store"`   // "Root", "CA", "Disallowed"
	TargetStore   string    `json:"target_store"`
	RollbackID    string    `json:"rollback_id"`
	Success       bool      `json:"success"`
	ErrorMessage  string    `json:"error_message,omitempty"`
}

// Log 记录审计日志
func (l *Logger) Log(entry AuditEntry) error {
	if entry.Timestamp.IsZero() {
		entry.Timestamp = time.Now()
	}

	// 生成日志文件名（按日期）
	logFile := filepath.Join(l.logDir, fmt.Sprintf("audit_%s.jsonl",
		entry.Timestamp.Format("2006-01-02")))

	// 打开文件（追加模式）
	f, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		return fmt.Errorf("打开日志文件失败: %w", err)
	}
	defer f.Close()

	// 写入 JSON 行
	encoder := json.NewEncoder(f)
	if err := encoder.Encode(entry); err != nil {
		return fmt.Errorf("写入日志失败: %w", err)
	}

	// 同时输出到控制台
	l.printLog(entry)

	return nil
}

// printLog 打印日志到控制台
func (l *Logger) printLog(entry AuditEntry) {
	status := "成功"
	if !entry.Success {
		status = fmt.Sprintf("失败: %s", entry.ErrorMessage)
	}

	fmt.Printf("[%s] %s: %s (%s -> %s) - %s\n",
		entry.Timestamp.Format("2006-01-02 15:04:05"),
		entry.Operation,
		entry.Thumbprint,
		entry.SourceStore,
		entry.TargetStore,
		status,
	)
}

// GenerateRollbackID 生成回滚 ID
func GenerateRollbackID() string {
	return fmt.Sprintf("%s_%04x",
		time.Now().UTC().Format("2006-01-02T15-04-05Z"),
		time.Now().UnixNano()%0x10000,
	)
}

// CreateBackup 创建备份快照
func (l *Logger) CreateBackup(rollbackID string, data []byte) error {
	backupFile := filepath.Join(l.backupDir, fmt.Sprintf("backup_%s.json", rollbackID))

	if err := os.WriteFile(backupFile, data, 0644); err != nil {
		return fmt.Errorf("创建备份文件失败: %w", err)
	}

	fmt.Printf("已创建备份快照: %s\n", backupFile)
	return nil
}

// CleanupOldBackups 清理过期的备份文件
func (l *Logger) CleanupOldBackups(retentionDays int) error {
	if retentionDays <= 0 {
		return nil // 永久保留
	}

	cutoffTime := time.Now().AddDate(0, 0, -retentionDays)

	entries, err := os.ReadDir(l.backupDir)
	if err != nil {
		return fmt.Errorf("读取备份目录失败: %w", err)
	}

	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}

		info, err := entry.Info()
		if err != nil {
			continue
		}

		if info.ModTime().Before(cutoffTime) {
			backupPath := filepath.Join(l.backupDir, entry.Name())
			if err := os.Remove(backupPath); err != nil {
				fmt.Printf("警告: 删除过期备份失败: %s: %v\n", entry.Name(), err)
			} else {
				fmt.Printf("已删除过期备份: %s\n", entry.Name())
			}
		}
	}

	return nil
}
